package io.wjc.config;

import io.wjc.common.RsaUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.util.ResourceUtils;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.security.interfaces.RSAPublicKey;

/**
 * 资源服务的自动装配类，这里可以引入一个配置类（使用@EnableConfigurationProperties），动态配置某些属性
 * @see @EnableOauthResourceServer
 */
@Slf4j
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) //这个注解放到@EnableOauthResourceServer里面不生效，没有加载InfrastructureAdvisorAutoProxyCreator类，有兴趣的研究下
@ConditionalOnMissingBean(TokenStore.class)
public class OauthResourceServerAutoConfiguration extends ResourceServerConfigurerAdapter {
//	private String SIGNING_KEY = "abc123";

	@Value("${spring.application.name}")
	private String RESOURCE_ID;
	/**
	 * 默认资源服务安全配置，可以通过
	 *
	 * @param http
	 */
	@Override
	@SneakyThrows
	public void configure(HttpSecurity http) {
		http
				.authorizeRequests()
				.antMatchers("/**").access("#oauth2.hasScope('read')")
				.and().csrf().disable()
				.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
	}

	@Override
	public void configure(ResourceServerSecurityConfigurer resources) {
		resources
//				.authenticationEntryPoint(resourceAuthExceptionEntryPoint) //配置auth fail point
//				.accessDeniedHandler(accessDeniedHandler) //配置token验证失败信息
//				.tokenServices(tokenService()) //配置token验证服务，jwt token不需要配置
				.resourceId(RESOURCE_ID) //资源 ID，这里取app name
				.tokenStore(tokenStore()) //token管理器
				.stateless(true)
		;
	}

	@Bean
	@Primary
	@LoadBalanced
	@ConditionalOnMissingBean(RestTemplate.class)
	public RestTemplate lbRestTemplate() {
		RestTemplate restTemplate = new RestTemplate();
		restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
			@Override
			@SneakyThrows
			public void handleError(ClientHttpResponse response) {
				if (response.getRawStatusCode() != HttpStatus.BAD_REQUEST.value()) {
					super.handleError(response);
				}
			}
		});
		return restTemplate;
	}

//	/**
//	 * 资源服务令牌解析服务，此例中因为使用的是基于客户端的jwt token所以这个类用不到
//	 */
//    @Bean
//    public ResourceServerTokenServices tokenService() {
//        //使用远程服务请求授权服务器校验token,必须指定校验token 的url、client_id，client_secret
//        RemoteTokenServices service=new RemoteTokenServices();
//        service.setCheckTokenEndpointUrl("http://localhost:53020/auth/oauth/check_token");
//        service.setClientId("wnApp");
//        service.setClientSecret("123456");
//
//        //用户信息token转换器，这种token是默认的token方式，没有增强，如果使用jwt增强了的token，使用JwtAccessTokenConverter转换器
//		DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
//		accessTokenConverter.setUserTokenConverter(userTokenConverter);
//
//		service.setRestTemplate(lbRestTemplate());
//		service.setAccessTokenConverter(accessTokenConverter);
//
//        return service;
//    }

	@Bean
	public TokenStore tokenStore() {
		//JWT令牌存储方案
		return new JwtTokenStore(accessTokenConverter());
	}

	@Bean
	public JwtAccessTokenConverter accessTokenConverter() {
		JwtAccessTokenConverter converter = new JwtAccessTokenConverter();

		//对称秘钥，资源服务器使用该秘钥来验证
		//converter.setSigningKey(SIGNING_KEY);

		//非对接加密
		try {
			File pubKeyFile = ResourceUtils.getFile("classpath:rsa/id_key_rsa.pub");
			RsaVerifier rsaVerifier = new RsaVerifier((RSAPublicKey) RsaUtils.getPublicKey(pubKeyFile.getPath()));
			converter.setVerifier(rsaVerifier);
		} catch (Exception e) {
			log.error("加载证书公钥文件出错：",e);
		}
		return converter;
	}
}
